/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * $Id: ImageLoader.java 491 2007-10-12 17:25:56Z metlov $
 *
 * This file is part of the Java Expressions Library (JEL).
 *   For more information about JEL visit :
 *    http://kinetic.ac.donetsk.ua/JEL/
 *
 * (c) 1998 -- 2007 by Konstantin Metlov(metlov@kinetic.ac.donetsk.ua);
 *
 * JEL is Distributed under the terms of GNU General Public License.
 *    This code comes with ABSOLUTELY NO WARRANTY.
 *  For license details see COPYING file in this directory.
 */

package gnu.jel;
import gnu.jel.debug.Debug;

/**
 * Loads JEL-generated classes into Java VM.
 * <P> Specifics of JEL generated classes is that the class name UTF8 is always
 * the first entry in the constant pool. This loader will not load 
 * other classes.
 */
public class ImageLoader extends ClassLoader {
  String name;
  byte[] bytes;
  Class c;
  ClassLoader parent;
  
  private ImageLoader(String name, byte[] bytes) {
    this.name=name;
    this.bytes=bytes;
    this.c=null;
    this.parent=this.getClass().getClassLoader();
  };
  

  /**
   * Loads given JEL-generated image under its own name.
   * @param image to load
   * @return the class object for the new class or <TT>null</TT> 
   *         if unsuccessful.
   */
  public static Class load(byte[] image) {
    if (Debug.enabled)
      Debug.check(image[10]==1,
                   "Attempt to load non-JEL generated class file");
      
    // JEL generated class file never have UNICODE class name
    // although they might reference UNICODE methods, etc...
    int len=(image[11]<<8)+image[12];
    char[] nameChr=new char[len];
    for(int i=0;i<len;i++) nameChr[i]=(char)image[13+i];
    String name=String.copyValueOf(nameChr);
    
    try {
      // load class
      ImageLoader il=new ImageLoader(name,image);
      return il.loadClass(name);
    } catch(Exception e) {
      if (Debug.enabled)
        Debug.reportThrowable(e);
    };
    return null;
  };


//    // Please uncomment the code below and use it for loading expressions
//    // (e.g. by commenting the "load" method above and renaming
//    // "loadRenamed"->"load" below) if You have an older version
//    // of JDK (below 1.1.7, AFAIK), which does not allow classes with
//    // the _same_ names to be loaded by _different_ classloaders.
//    //
//    // Number of loaded expressions in this session
//    private transient volatile static long expressionUID=0;

//    /**
//     * Prefix of the expression classname
//     * <P>Example: "gnu.jel.generated.E_"
//     */
//    public static String classNamePrefix="gnu.jel.generated.E_";

//    /**
//     * Loads given JEL-generated image under unique name.
//     * <P>The unique name is generated by appending a steadily incremented
//     * number to the <TT>classNamePrefix</TT>.
//     * @param image to load
//     * @return the class object for the new class or <TT>null</TT> 
//     *         if unsuccessful.
//     * @see gnu.jel.ImageLoader#classNamePrefix
//     */
//    public static Class loadRenamed(byte[] image) {
//      if (Debug.enabled)
//        Debug.check(image[10]==1,
//                     "Attempt to load non-JEL generated class file");

//      String newname=classNamePrefix+Long.toString(expressionUID++);
//      String newnameHF=TypesStack.toHistoricalForm(newname);

//      // JEL generated class file never have UNICODE class name
//      // although they might reference UNICODE methods, etc...
//      int len=(image[11]<<8)+image[12];
//      int newlen=newname.length();
    
//      byte[] newimage=new byte[image.length-len+newlen];
    
//      System.arraycopy(image,0,newimage,0,11);
//      newimage[11]=(byte)(newlen>>8);
//      newimage[12]=(byte)newlen;
//      for(int i=0;i<newlen;i++)
//        newimage[13+i]=(byte)newnameHF.charAt(i);
//      System.arraycopy(image,13+len,newimage,13+newlen,image.length-13-len);

//      try {
//        // load class
//        ImageLoader il=new ImageLoader(newname,newimage);
//        return il.loadClass(newname);
//      } catch(Exception e) {
//        if (Debug.enabled)
//          Debug.reportThrowable(e);
//      };
    
//      return null;
//    };

  protected synchronized Class loadClass(String name, boolean resolve) throws
  java.lang.ClassNotFoundException  {
    if (!name.equals(this.name)) {
      if (parent!=null) 
        return parent.loadClass(name);
      else
        return findSystemClass(name);
    } else {
      if(c==null) {
        c = defineClass(name,bytes, 0, bytes.length,this.getClass().getProtectionDomain());
        if (resolve) resolveClass(c);
      }
      return c;
    }
  };  
};

